﻿using System;
using System.Reflection;

namespace CSW.Framework.Linq
{
    /// <summary>
    /// FieldInfoWrapper
    /// </summary>
    public class FieldInfoWrapper
    {
        private readonly FieldInfo m_Field;
        private readonly FieldInfo m_FieldLoaded;
        private const BindingFlags bf = BindingFlags.NonPublic | BindingFlags.Instance;

        internal FieldInfoWrapper(Type type, string propertyName)
        {
            string fieldName = "m_" + propertyName + "FromDb";
            m_Field = type.GetField(fieldName, bf);
            if (m_Field == null)
                throw new Exception(string.Format("Field '{0}' not found in type '{1}'.", fieldName, type.FullName));
            
            fieldName = "m_Is" + propertyName + "LoadedFromDb";
            m_FieldLoaded = type.GetField(fieldName, bf);
            if (m_FieldLoaded == null)
                throw new Exception(string.Format("Field '{0}' not found in type '{1}'.", fieldName, type.FullName));
        }

        internal void SetValue(object obj, object value)
        {
            if (m_Field.FieldType == typeof(sbyte?) && value is byte)
            {
                sbyte? sbyteValue = (sbyte?)(byte?)value;
                m_Field.SetValue(obj, sbyteValue);
                m_FieldLoaded.SetValue(obj, true);
            }
            else
            {
                m_Field.SetValue(obj, value);
                m_FieldLoaded.SetValue(obj, true);
            }
        }

        internal object GetValue(object obj)
        {
            if ((bool)m_FieldLoaded.GetValue(obj) == false)
                throw new Exception(string.Format("'{0}' had not been loaded.", m_Field.Name));

            return m_Field.GetValue(obj);
        }

        internal void ClearValue(object obj)
        {
            m_Field.SetValue(obj, null);
            m_FieldLoaded.SetValue(obj, false);
        }
    }
}
